package server.main.config.springsecurity;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import server.main.config.springsecurity.config.*;
//import server.main.config.springsecurity.fliter.CustomAuthenticationFilter;
import server.main.config.springsecurity.fliter.CaptchaFilter;
import server.main.service.AccountService;
import server.main.service.CaptchaService;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

/**
 * @auther MingHsZzz
 * @create 2022-08-30-10:57
 */

@Slf4j
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CommonWebMvcConfigurer commonWebMvcConfigurer;

    @Autowired
    AccountService accountService;

    @Autowired
    UserDetailsService userDetailsService;

    @Autowired
    MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;

    @Autowired
    MyAuthenticationFailHandler myAuthenticationFailHandler;

    @Autowired
    CaptchaFilter captchaFilter;

    /**
     * 认证设置（配置用户信息：登录名、登录密码、所属角色）
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(password());
        log.info("认证设置（配置用户信息：登录名、登录密码、所属角色）设置完成");
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        // 静态资源
        String[] ignoreArray = commonWebMvcConfigurer.getStatic();
        // 设置系统的静态资源。静态资源不会走权限框架
        web.ignoring().antMatchers(ignoreArray);

    }

    /**
     * 认证设置（HttpSecurity认证，用户请求URL认证）
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 只有这些URL需要拦截并识别验证码
        // captchaFilter.setMatchers("/userlogin", "/before/forget",
        // "/before/register");

        // http.addFilterBefore(captchaFilter,
        // UsernamePasswordAuthenticationFilter.class);

        log.info("filter配置完成");

        // http.formLogin()
        // .loginPage("/pages/login.html")
        // .loginProcessingUrl("/userlogin")
        // //自定义登录成功处理类
        // .successHandler(myAuthenticationSuccessHandler)
        // //自定义登录失败处理类
        // .failureHandler(myAuthenticationFailHandler)
        // .permitAll()
        // .and()
        // .headers().frameOptions().disable()
        // .and()
        // // authorizeRequests()方法表示开启HttpSecurity认证
        // .authorizeRequests()
        // .antMatchers("/js/**", "/css/**", "/fonts/**", "/img/**", "/icons/**",
        // "/plugins/**", "/element-theme/**", "/pages/before/**").permitAll()
        // .antMatchers("/checkLogin", "/login", "/before/**").permitAll()
        // //其余请求都要进行授权认证
        // .anyRequest().authenticated()
        // .and().csrf().disable();
        http.formLogin()
                .loginPage("/pages/before/login.html").permitAll()
                .loginProcessingUrl("/userlogin").permitAll()
                // 自定义登录成功处理类
                .successHandler(myAuthenticationSuccessHandler)
                // 自定义登录失败处理类
                .failureHandler(myAuthenticationFailHandler)
                .permitAll()
                .and()
                .headers().frameOptions().disable()
                .and()
                // authorizeRequests()方法表示开启HttpSecurity认证
                .authorizeRequests()
                // .antMatchers("/js/**", "/css/**", "/fonts/**", "/img/**", "/icons/**",
                // "/plugins/**", "/element-theme/**", "/pages/before/**").permitAll()
                .antMatchers(commonWebMvcConfigurer.getNoFilterUrl()).permitAll()
                // 其余请求都要进行授权认证
                .anyRequest().authenticated()
                .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
                    public <O extends FilterSecurityInterceptor> O postProcess(O object) {
                        // 权限查询器
                        // 设置你有哪些权限
                        object.setSecurityMetadataSource(new CustomerFilterInvocationSecurityMetadataSource());

                        // 权限决策器
                        // 判断你有没有权限访问当前的url
                        object.setAccessDecisionManager(new CustomerAccessDecisionManger());
                        return object;
                    }
                })
                .and().csrf().disable();

        // 登出设置
        http.logout()
                .logoutUrl("/logout")
                .deleteCookies()
                .invalidateHttpSession(true)
                .clearAuthentication(true)
                .logoutSuccessHandler(((req, resp, authentication) -> {
                    resp.setContentType("application/json;charset=utf-8");
                    PrintWriter out = resp.getWriter();
                    Map<String, Object> objectMap = new HashMap<>(2);
                    objectMap.put("code", 0);
                    objectMap.put("msg", "注销成功");
                    out.write(JSONObject.toJSONString(objectMap));
                    out.flush();
                    out.close();
                }))
                .permitAll();
        log.info("认证设置（HttpSecurity认证，用户请求URL认证）设置完成");
    }

    /**
     * 密码加密方式，必须指定一种
     * 本例使用官方推荐的BCrypt强哈希函数，密钥迭代次数为2^strength，strength取值在4~31之间，默认为10
     */
    @Bean
    PasswordEncoder password() {
        // System.out.println("");
        return new BCryptPasswordEncoder();
    }

}
